/* Copyright Thanh-Trung Pham, 2015 */
package jp.ac.uaizu.translation;

import jp.ac.uaizu.message.SerCompMessageResource;
import jp.ac.uaizu.message.SerCompMessageUtility;
import jp.ac.uaizu.message.SerCompTranslatorsException;

import java.io.File;
import java.io.FilenameFilter;
import java.net.MalformedURLException;
import java.net.URL;
import java.net.URLClassLoader;

/**
 * @author Thanh-Trung Pham
 */
public class SerCompTranslators {
    private ClassLoader m_oClassLoader;
    private String m_strTranslatorsFolderName;

    /**
     * The constructor.
     *
     * @param translatorsFolderName the translators's folder name.
     * @throws SerCompTranslatorsException if there is an error.
     */
    public SerCompTranslators(String translatorsFolderName) throws SerCompTranslatorsException {
        m_strTranslatorsFolderName = translatorsFolderName;
        initialize();
    }

    /**
     * Initializer.
     *
     * @throws SerCompTranslatorsException if there is an error.
     */
    private void initialize() throws SerCompTranslatorsException {
        File oTranslatorsFolder = new File(m_strTranslatorsFolderName);

        if (!oTranslatorsFolder.exists()) {
            throw new SerCompTranslatorsException(SerCompMessageUtility.getResourceMessage(SerCompMessageResource.TRANSLATORS_FOLDER_NOT_EXISTING, m_strTranslatorsFolderName));
        }

        if(oTranslatorsFolder.isFile()){
            throw new SerCompTranslatorsException(SerCompMessageUtility.getResourceMessage(SerCompMessageResource.TRANSLATORS_FOLDER_EXPECTED, m_strTranslatorsFolderName));
        }
    }

    /**
     * Prepare the class loader.
     *
     * @throws SerCompTranslatorsException if there is an error.
     */
    private void prepareClassLoader() throws SerCompTranslatorsException {
        File oTranslatorsFolder = new File(m_strTranslatorsFolderName);

        FilenameFilter oFilter = new FilenameFilter() {
            public boolean accept(File dir, String name) {
                return name.endsWith(".jar");
            }
        };

        File[] oJarFiles = oTranslatorsFolder.listFiles(oFilter);
        URL[] oURLs = new URL[oJarFiles.length + 1];

        try {
            oURLs[0] = oTranslatorsFolder.toURI().toURL();
            for (int i = 0; i < oJarFiles.length; i++) {
                oURLs[i + 1] = oJarFiles[i].toURI().toURL();
            }
        } catch (MalformedURLException oEx) {
            throw new SerCompTranslatorsException(SerCompMessageUtility.getResourceMessage(SerCompMessageResource.TRANSLATORS_UNEXPECTED_EXCEPTION, oEx.getMessage()));
        }

        m_oClassLoader = new URLClassLoader(oURLs);
    }


    /**
     * Get a translator by name.
     *
     * @param translatorName the name of the translator.
     * @return the registered translator.
     * @throws SerCompTranslatorsException if there is an error.
     */
    public ISerCompTranslator getTranslator(String translatorName) throws SerCompTranslatorsException {
        prepareClassLoader();

        try {
            Class oTranslatorClass = m_oClassLoader.loadClass(translatorName);
            checkRequirements(translatorName, oTranslatorClass);

            return (ISerCompTranslator) oTranslatorClass.newInstance();
        } catch (ClassNotFoundException oEx) {
            throw new SerCompTranslatorsException(SerCompMessageUtility.getResourceMessage(SerCompMessageResource.TRANSLATORS_NOT_FOUND, translatorName, m_strTranslatorsFolderName));
        } catch (InstantiationException oInstantiationException) {
            throw new SerCompTranslatorsException(SerCompMessageUtility.getResourceMessage(SerCompMessageResource.TRANSLATORS_UNEXPECTED_EXCEPTION, oInstantiationException.getMessage()));
        } catch (IllegalAccessException oIllegalAccessException) {
            throw new SerCompTranslatorsException(SerCompMessageUtility.getResourceMessage(SerCompMessageResource.TRANSLATORS_UNEXPECTED_EXCEPTION, oIllegalAccessException.getMessage()));
        }


    }

    /**
     * Check the requirements for a translator.
     *
     * @param translatorName  the translator's name.
     * @param translatorClass the translator's class
     * @throws SerCompTranslatorsException if there is an error.
     */
    private void checkRequirements(String translatorName, Class translatorClass) throws SerCompTranslatorsException {
        if (translatorClass.isInterface()) {
            throw new SerCompTranslatorsException(SerCompMessageUtility.getResourceMessage(SerCompMessageResource.TRANSLATORS_NOT_CLASS));
        }

        Class[] oInterfaces = translatorClass.getInterfaces();

        boolean isImplementedTranslationInterface = false;
        for (Class oInterface : oInterfaces) {
            if (oInterface.getName().equals(ISerCompTranslator.class.getName())) {
                isImplementedTranslationInterface = true;
            }
        }

        if (!isImplementedTranslationInterface) {
            throw new SerCompTranslatorsException(SerCompMessageUtility.getResourceMessage(SerCompMessageResource.TRANSLATORS_MISSING_INTERFACE, translatorName, ISerCompTranslator.class.getName()));
        }
    }
}
